package com.mew.common.dc.db;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mew.common.config.RedisConstantValue;
import com.mew.common.dc.mapper.GameMapper;
import com.mew.common.dc.mapper.JackportMapper;
import com.mew.common.dc.mapper.RoomMapper;
import com.mew.common.dc.mapper.RoomProfileMapper;
import com.mew.common.enm.DataStateType;
import com.mew.common.entity.config.Game;
import com.mew.common.entity.config.Room;
import com.mew.common.entity.game.Jackport;
import com.mew.common.entity.game.RoomProfile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 下线的游戏， 直接从redis 移除 ；  如果房间关闭完了 则游戏也自动关闭
 * 房间下线： 直接从房间列表移除
 * @Author King.Song
 * @Date 2020/11/23 0023
 **/
@Service
@Slf4j
public class GameRoomService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private GameMapper gameMapper;
    @Autowired
    private RoomMapper roomMapper;
    @Autowired
    private RoomProfileMapper roomProfileMapper;
    @Autowired
    private JackportMapper jackportMapper;
    @Autowired
    private DefaultRedisScript<Long> roomProfileScript;


    //下线的游戏， 直接从redis 移除 ；  如果房间关闭完了 则游戏也自动关闭
    public void loadRoomGame()throws Exception{
        redisTemplate.delete(RedisConstantValue.GAMECONF_GAME);
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Game>()
                .eq(Game::getState, DataStateType.Active.code());
        List<Game> list = gameMapper.selectList(queryWrapper);
        doLoadGameConfig(list);
    }

    //下线的游戏， 直接从redis 移除 ；  如果房间关闭完了 则游戏也自动关闭
    public void loadRoomGame(List<Integer> gameIds)throws Exception{
        List<Game> list = gameMapper.selectBatchIds(gameIds);
        doLoadGameConfig(list);
    }


    public Game getRedisGame(int gameId){
        if (gameId <1){
            return null;
        }
        return  (Game) redisTemplate.opsForHash().get(RedisConstantValue.GAMECONF_GAME, gameId);
    }


    private void doLoadGameConfig(List<Game> gameList)throws Exception{
        if (null == gameList || gameList.isEmpty()){
            throw new Exception("----game is null --------");
        }
        List<RoomProfile> roomPList = new ArrayList<>();
        gameList.forEach(game -> {
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Room>()
                    .eq(Room::getGameId, game.getId())
                    .eq(Room::getState, DataStateType.Active.code());
            List<Room> list = roomMapper.selectList(queryWrapper);
            if (!(null == list || list.isEmpty())){

                roomPList.addAll(loadRoomProfile(list));
                loadRoomJackPort(list);

                String roomKey = String.format(RedisConstantValue.GAMECONF_ROOM_LIST, game.getId());
                redisTemplate.delete(roomKey);
                list.forEach(room -> redisTemplate.opsForList().leftPush(roomKey, room));

                redisTemplate.opsForHash().put(RedisConstantValue.GAMECONF_GAME, game.getId(), game);
            }
        });

        for (RoomProfile roomProfile : roomPList){
            redisTemplate.opsForHash().put(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomProfile.getRoomId(), roomProfile);
        }
    }


    private int loadRoom(int gameId){
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Room>()
                .eq(Room::getGameId, gameId)
                .eq(Room::getState, DataStateType.Active.code());
        List<Room> list = roomMapper.selectList(queryWrapper);
        if (null == list || list.isEmpty()){
            return 0;
        }

        loadRoomProfile(list);
        loadRoomJackPort(list);

        String roomKey = String.format(RedisConstantValue.GAMECONF_ROOM_LIST, gameId);
        redisTemplate.delete(roomKey);
        list.forEach(room -> redisTemplate.opsForList().leftPush(roomKey, room));
        return list.size();
    }

    public List<RoomProfile> loadRoomProfile(List<Room> list){
        List<RoomProfile> rpList = new ArrayList<>(list.size());
        for (Room room : list){
            RoomProfile roomProfile = (RoomProfile) redisTemplate.opsForHash().get(RedisConstantValue.GAMECONF_ROOM_PROFILE, room.getId());
            if (null != roomProfile){
                roomProfileMapper.updateById(roomProfile);
                redisTemplate.opsForHash().delete(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomProfile.getRoomId());
            }
            roomProfile = roomProfileMapper.selectById(room.getId());
            if (null == roomProfile){
                roomProfile = new RoomProfile();
                roomProfile.setRoomId(room.getId());
                roomProfile.setRoomType(room.getRoomType());
                roomProfileMapper.insert(roomProfile);
                roomProfile = roomProfileMapper.selectById(room.getId());
            }
            rpList.add(roomProfile);
//            redisTemplate.opsForHash().put(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomProfile.getRoomId(), roomProfile);
        }
        return rpList;
    }

    public void testRoomP(){
        List<Room> rooms = findRoomAllByDB();
        for (Room room : rooms){
            RoomProfile profile = roomProfileMapper.selectById(room.getId());
            log.info("rom {}", room.toString());
            long roomId = profile.getRoomId();
            redisTemplate.opsForHash().put("U:RP", roomId, profile);
        }
    }
    public List<Game> testGame(){
        redisTemplate.delete(RedisConstantValue.GAMECONF_GAME);
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Game>()
                .eq(Game::getState, DataStateType.Active.code());
        List<Game> list = gameMapper.selectList(queryWrapper);

       return list;
    }

    /**
     * 加载奖池
     */
    private void loadRoomJackPort(List<Room> roomList){
        roomList.forEach(room->{
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Jackport>()
                    .eq(Jackport::getRoomId, room.getId());
            List<Jackport> list = jackportMapper.selectList(queryWrapper);
            list.forEach(jackPort-> redisTemplate.opsForHash().put(String.format(RedisConstantValue.GAMECONF_ROOM_JACKPOT_REAL, room.getId())
                    ,jackPort.getNo(),jackPort));
        });
    }


    public List<Room> findRoomAllByDB(){
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Room>()
                .eq(Room::getState, DataStateType.Active.code());
        return roomMapper.selectList(queryWrapper);
    }

    public List<Room> findRoomByGameId(int gameId){
        if (gameId <1){
            return null;
        }
        List<Object> list = redisTemplate.opsForList().range(String.format(RedisConstantValue.GAMECONF_ROOM_LIST, gameId), 0, -1);
        if (null == list || list.isEmpty()){
            return null;
        }
        return list.stream().map(o -> (Room)o).collect(Collectors.toList());
    }

    public Room getRedisRoom(int gameId, int roomId){
        if (roomId <1){
            return null;
        }
        List<Room> list = findRoomByGameId(gameId);
        if (null == list || list.isEmpty()){
            return null;
        }
        return list.stream().filter(r -> roomId == r.getId()).findFirst().orElse(null);
    }


    public void updateRoom(Room room){
        roomMapper.updateById(room);
    }


    public void updateRedisRoom(Room room){
        List<Object> list = redisTemplate.opsForList().range(String.format(RedisConstantValue.GAMECONF_ROOM_LIST, room.getGameId()), 0, -1);
        if (null == list || list.isEmpty()){
            return;
        }

        int index = -1;
        Room tr;
        for (int i=0; i<list.size(); i++){
            tr = (Room) list.get(i);
            if (room.equals(tr)){
                index = i;
                break;
            }
        }

        if (index == -1){
            return;
        }
        redisTemplate.opsForList().set(String.format(RedisConstantValue.GAMECONF_ROOM_LIST, room.getGameId()), index, room);
    }



    public void reloadRoomProfile(List<Integer> ids){
        List<RoomProfile> roomProfiles = roomProfileMapper.selectBatchIds(ids);
        for (RoomProfile roomProfile : roomProfiles){
            redisTemplate.opsForHash().put(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomProfile.getRoomId(), roomProfile);
        }
    }

    public RoomProfile getRoomProfile(int roomId){

        RoomProfile roomProfile = (RoomProfile) redisTemplate.opsForHash().get(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomId);
        if (roomProfile == null){
            roomProfile = roomProfileMapper.selectById(roomId);
            if (null != roomProfile){
                redisTemplate.opsForHash().put(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomId, roomProfile);
            }
        }
        return roomProfile;
    }


    public void updateRoomProfile(int roomId){
        RoomProfile roomProfile = (RoomProfile) redisTemplate.opsForHash().get(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomId);
        if (null != roomProfile){
            roomProfileMapper.updateById(roomProfile);
        }
    }

    public void updateRoomProfile(RoomProfile other, RoomProfile roomProfile){
        roomProfileMapper.updateById(other);
        redisTemplate.opsForHash().put(RedisConstantValue.GAMECONF_ROOM_PROFILE, roomProfile.getRoomId(), roomProfile);
    }

    //========= 奖池 ================

    /**
     * 通过房间 获取奖池
     */
    public List<Jackport> findJackPortByRoomId(int roomId){
        List<Object> list = redisTemplate.opsForHash().values(String.format(RedisConstantValue.GAMECONF_ROOM_JACKPOT_REAL, roomId));
        if (null == list || list.isEmpty()){
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Jackport>()
                    .eq(Jackport::getRoomId,roomId);
            list = jackportMapper.selectList(queryWrapper);
            if (null == list || list.isEmpty()){
                return null;
            }
            list.forEach(jackPort->{
                Jackport jack=(Jackport) jackPort;
                redisTemplate.opsForHash().put(String.format(RedisConstantValue.GAMECONF_ROOM_JACKPOT_REAL, roomId)
                    ,jack.getNo(),jack);
            });
        }
        return list.stream().map(o -> (Jackport)o).collect(Collectors.toList());
    }

    /**
     * 更新奖池
     * @param jackport
     */
    public void updateJackPort(int roomId,Jackport jackport){
        redisTemplate.opsForHash().put(String.format(RedisConstantValue.GAMECONF_ROOM_JACKPOT_REAL, roomId)
                ,jackport.getNo(),jackport);
/*        Jackport temp=new Jackport();
        temp.setId(jackport.getId());
        temp.setVal(jackport.getVal());
        jackportMapper.updateById(temp);*/
    }

    public long doLua(int roomId, long betNumber, long paymentNumber,
                      long temp_blood_n,
                      long balance_end_n, int small_end_n, int big_end_n,
                      int plan_type_n,
                      double small_wave_fold, double big_wave_fold,
                      long wave_cheat){
        long res =  redisTemplate.execute(roomProfileScript, Arrays.asList(String.valueOf(roomId)), betNumber, paymentNumber,
                1000000, temp_blood_n, 0,
                balance_end_n, small_end_n, big_end_n,
                plan_type_n,
                small_wave_fold, big_wave_fold,
                wave_cheat
        );
        return res;
    }

    public long doLua(long gameId, long betNumber){
        long res =  redisTemplate.execute(roomProfileScript, Arrays.asList(String.valueOf(gameId)), betNumber);
        return res;
    }

    public long doAdd(int roomId){
        RoomProfile roomProfile = roomProfileMapper.selectById(roomId);

        redisTemplate.opsForHash().put("T:RP", roomProfile.getRoomId(), roomProfile);
        return 0;
//        RedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
//        long res = redisTemplate.execute(roomProfileSetScript, valueSerializer, valueSerializer, Arrays.asList("ROOMP{mykey}"+String.valueOf(roomProfile.getRoomId())), roomProfile);
//
//        RoomProfile roomProfile1 = getRoomProfile(roomProfile.getRoomId());
//        log.info("--------------{}----", roomProfile1.toString());
//        return res;
    }




}

